package spring.framework.beans.factory.support;

import spring.framework.beans.BeansException;
import spring.framework.beans.factory.FactoryBean;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author fun.pengzh
 * @class spring.framework.beans.factory.support.FactoryBeanRegistrySupport
 * @desc
 * @since 2021-11-13
 */
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
    /**
     * Cache of singleton objects created by FactoryBeans: FactoryBean name --> object
     */
    private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>();

    protected Object getCachedObjectForFactoryBean(String beanName) {
        Object ojbect = this.factoryBeanObjectCache.get(beanName);
        return (ojbect != NULL_OBJECT ? ojbect : null);
    }

    protected Object getObjectFromFactoryBean(String beanName, FactoryBean factoryBean) {
        if (factoryBean.isSingleton()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = doGetObjectFromFactoryBean(beanName, factoryBean);
                this.factoryBeanObjectCache.put(beanName, (object != null) ? object : NULL_OBJECT);
            }
            return object != NULL_OBJECT ? object : null;
        } else {
            return doGetObjectFromFactoryBean(beanName, factoryBean);
        }
    }

    private Object doGetObjectFromFactoryBean(final String beanName, final FactoryBean factoryBean) {
        try {
            return factoryBean.getObject();
        } catch (Exception e) {
            throw new BeansException("FactoryBean throw new exception on object[" + beanName + "] creation:", e);
        }
    }

}
